package com.xuecheng.manage_media.service;

import com.alibaba.fastjson.JSON;
import com.xuecheng.framework.domain.media.MediaFile;
import com.xuecheng.framework.domain.media.response.CheckChunkResult;
import com.xuecheng.framework.domain.media.response.MediaCode;
import com.xuecheng.framework.exception.CustomExcetionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.manage_media.config.RabbitMQConfig;
import com.xuecheng.manage_media.dao.MediaFileRepository;
import org.apache.commons.io.IOUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

@Service
public class MediaService {
    @Value("${xc-service-manage-media.upload-location}")
    String dir;
    @Autowired
    MediaFileRepository mediaFileRepository;

    /**
     * @Description: 上传分块注册 进行检查
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public ResponseResult fileRegister(String fileMd5, String fileName, Long fileSize, String mimetype, String fileExt) {
//        判断文件夹中文件是否存在
        String filePath = getFilePath(fileMd5, fileExt);
        File file = new File(filePath);
//        判断数据库中是否有信息
        Optional<MediaFile> optionalMediaFile = mediaFileRepository.findById(fileMd5);
        if (optionalMediaFile.isPresent() && file.exists()) {
//            存在直接返回
            throw CustomExcetionCast.getCusException(MediaCode.CHUNK_FILE_EXIST_CHECK);
        }
//        创建目录
        String dirPath = getDirPath(fileMd5);
        File fileDir = new File(dirPath);
        boolean mkdir = fileDir.mkdirs();

        return new ResponseResult(CommonCode.SUCCESS);
    }

    /**
     * @Description: 获取文件绝对路径
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    private String getFilePath(String fileMd5, String fileExt) {
//        一级目录
        String one = fileMd5.substring(0, 1);
//        二级目录
        String two = fileMd5.substring(1, 2);
        return dir + one + "/" + two + "/" + fileMd5 + "/" + fileMd5 + "." + fileExt;
    }

    /**
     * @Description: 获取文件相对路径
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    private String getRelFilePath(String fileMd5, String fileExt) {
//        一级目录
        String one = fileMd5.substring(0, 1);
//        二级目录
        String two = fileMd5.substring(1, 2);
        return one + "/" + two + "/" + fileMd5 + "/";
    }

    /**
     * @Description: 创建分块文件目录
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    private String getDirPath(String fileMd5) {
//        一级目录
        String one = fileMd5.substring(0, 1);
//        二级目录
        String two = fileMd5.substring(1, 2);
        return dir + one + "/" + two + "/" + fileMd5 + "/chunk/";
    }

    /**
     * @Description: 检查块文件是否存在
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public CheckChunkResult checkchunk(String fileMd5, Integer chunk, Integer chunkSize) {


        String dirPath = getDirPath(fileMd5);
        File file = new File(dirPath + chunk);
        if (!file.exists()) {
            return new CheckChunkResult(MediaCode.CHUNK_FILE_EXIST_CHECK, false);
        }
        long length = file.length();
        if (length != chunkSize) {
            return new CheckChunkResult(MediaCode.CHUNK_FILE_EXIST_CHECK, false);
        }
        return new CheckChunkResult(MediaCode.CHUNK_FILE_EXIST_CHECK, true);
    }

    /**
     * @Description: 上传文件
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public ResponseResult uploadchunk(MultipartFile file, Integer chunk, String fileMd5) {
//        检查快文件夹是否存在
        String dirPath = getDirPath(fileMd5);
        File dirFile = new File(dirPath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }
//        创建目标文件
        File filePath = new File(dirPath + chunk);
//        得到输入流
        InputStream inputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            inputStream = file.getInputStream();
            fileOutputStream = new FileOutputStream(filePath);
            IOUtils.copy(inputStream, fileOutputStream);
//            写出到文件夹中
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return new ResponseResult(CommonCode.SUCCESS);
    }

    /**
     * @Description: 合并分块
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public ResponseResult mergechunks(String fileMd5, String fileName, Long fileSize, String mimetype, String fileExt) {
//        判断合并的文件是否存在
        if (StringUtils.isEmpty(fileMd5) || StringUtils.isEmpty(fileName)) {
            throw CustomExcetionCast.getCusException(CommonCode.INVALIDPARAM);
        }
        String dirPath = getFilePath(fileMd5, fileExt);
        File merge = new File(dirPath);

        try {
            if (merge.exists()) {
                merge.delete();
            } else {
                merge.createNewFile();
            }
//                将分块文件进行合并
            File mergeFile = mergeFile(fileMd5, merge);
            if (!mergeFile.exists()) {
                throw CustomExcetionCast.getCusException(MediaCode.MERGE_FILE_CHECKFAIL);
            }
            ;
            boolean b = checkMd5(fileMd5 + "." + fileExt, mergeFile);
            if (!b) {
                throw CustomExcetionCast.getCusException(MediaCode.MERGE_FILE_CHECKFAIL);
            }
            MediaFile mediaFile = new MediaFile();
            mediaFile.setFileName(fileName);
            //将文件信息保存到数据库
            mediaFile.setFileId(fileMd5);
            mediaFile.setFileName(fileMd5 + "." + fileExt);
            mediaFile.setFileOriginalName(fileName);
            //文件路径保存相对路径
            mediaFile.setFilePath(getRelFilePath(fileMd5, fileExt));
            mediaFile.setFileSize(fileSize);
            mediaFile.setUploadTime(new Date());
            mediaFile.setMimeType(mimetype);
            mediaFile.setFileType(fileExt);
            mediaFile.setProcessStatus("303001");
            mediaFile.setFileStatus("301001");

            mediaFileRepository.save(mediaFile);
//                通知RabbitMq客户端
           this.mediaProducer(fileMd5);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ResponseResult(CommonCode.SUCCESS);
    }

    /**
     * @Description: 合并文件私有方法
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    private File mergeFile(String fileMd5, File mergeFile) {
        String dirPath = getDirPath(fileMd5);
        File dir = new File(dirPath);
//        得到文件集合,排序进行合并
        File[] files = dir.listFiles();
        ArrayList<File> fileArrayList = new ArrayList<>();
        boolean b = fileArrayList.addAll(Arrays.asList(files));
        Collections.sort(fileArrayList, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                if (Integer.parseInt(o1.getName()) > Integer.parseInt(o2.getName())) {
                    return 1;
                } else {
                    return -1;
                }

            }
        });
//        分开合并到一个文件
//        创建写文件对象
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(mergeFile, "rw");
//            读取文件到缓冲区
            byte[] b1 = new byte[1024];
            for (File f : fileArrayList
            ) {
                RandomAccessFile read = new RandomAccessFile(f, "r");
                int len = -1;
//                读取文件
                while ((len = read.read(b1)) != -1) {
                    randomAccessFile.write(b1, 0, len);
                }
                read.close();
            }
            randomAccessFile.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mergeFile;
    }

    /**
     * @Description: 检验文件md5是否正确
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public boolean checkMd5(String fileMd5, File mergeFile) {
        String mergeFileName = mergeFile.getName();
        if (fileMd5.equals(mergeFileName)) {
            return true;
        } else {
            return false;
        }
    }

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Value("${xc-service-manage-media.mq.routingkey-media-video}")
    public  String routingkey_media_video;

    /**
     * @Description: mq生产端，发送消息
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public ResponseResult mediaProducer(String mediaId) {
        if (StringUtils.isEmpty(mediaId)) {
            throw CustomExcetionCast.getCusException(CommonCode.INVALIDPARAM);
        }
        Optional<MediaFile> optionalMediaFile = mediaFileRepository.findById(mediaId);
        if (!optionalMediaFile.isPresent()) {
            throw CustomExcetionCast.getCusException(CommonCode.SERVER_ERROR);
        }
        MediaFile mediaFile = optionalMediaFile.get();
        Map<String,String> map=new HashMap<>();
        map.put("mediaId",mediaId);
        String jsonString = JSON.toJSONString(map);
        try {
            rabbitTemplate.convertAndSend(RabbitMQConfig.EX_MEDIA_PROCESSTASK,routingkey_media_video,jsonString);
        } catch (AmqpException e) {
            e.printStackTrace();
            throw CustomExcetionCast.getCusException(CommonCode.FAIL);
        }
        return new ResponseResult(CommonCode.SUCCESS);
    }
}
